/****************************************
 * Copyright (c) 2015 NiuWa.
 * All rights reserved.
 * Created on 2015年4月16日
 * 
 * Contributors:
 * 	   bwz - initial implementation
 ****************************************/
package com.niuwa.p2p.service.impl.exchange;

import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.niuwa.p2p.core.utils.DateUtil;
import com.niuwa.p2p.core.utils.DictConstant;
import com.niuwa.p2p.dao.business.InvestProdRecordDao;
import com.niuwa.p2p.dao.business.InvestTransDao;
import com.niuwa.p2p.dao.business.LoanClaimDao;
import com.niuwa.p2p.dao.business.PlanProductDao;
import com.niuwa.p2p.dao.customer.CustomerDao;
import com.niuwa.p2p.dao.fund.AccountFlowDao;
import com.niuwa.p2p.dao.fund.BaseAccountDao;
import com.niuwa.p2p.dao.fund.CustAccountDao;
import com.niuwa.p2p.dao.fund.NwAccountDao;
import com.niuwa.p2p.dao.productTemplate.ProductDao;
import com.niuwa.p2p.dao.redenvelope.RedEnvelopeDao;
import com.niuwa.p2p.entity.business.InvestProdRecord;
import com.niuwa.p2p.entity.business.InvestTrans;
import com.niuwa.p2p.entity.customer.Customer;
import com.niuwa.p2p.entity.fund.AccountFlow;
import com.niuwa.p2p.entity.fund.BaseAccount;
import com.niuwa.p2p.entity.fund.CustAccount;
import com.niuwa.p2p.entity.productTemplate.Product;
import com.niuwa.p2p.service.exchange.BidService;
//import com.niuwa.p2p.service.exchange.IMatchService;
import com.niuwa.p2p.service.sequence.ISequenceService;
import com.niuwa.p2p.service.yeepay.YeePayService;
import com.niuwa.p2p.utils.ProgressUtils;
import com.niuwa.p2p.vo.business.InvestPlanProductVo;
import com.niuwa.p2p.vo.business.LoanClaimOriginVo;


/**
 * @title 立即投资相关操作
 *
 * @author bwz
 * @version 1.0
 * @created 2015年4月16日
 */
@Service
public class BidServiceImpl implements BidService {
	//TODO 交易相关review - 投标后回调操作
	
	@Autowired
	private ProductDao prodDao;
	
	@Autowired
	private PlanProductDao planProdDao;
	
	@Autowired
	private LoanClaimDao loanclaimDao;
	
	@Autowired
	private RedEnvelopeDao redEnvelopeDao;
	
	@Autowired
	private InvestProdRecordDao investProdDao;
	
	@Autowired
	private CustAccountDao custAcctDao;
	
	@Autowired
	private BaseAccountDao baseAcctDao;
	
	@Autowired
	private CustomerDao customerDao;
	
	@Autowired
	private InvestProdRecordDao investProdRecordDao;
	
	@Autowired
	private InvestTransDao investTransDao;
	
	@Autowired
	private AccountFlowDao acctFlowDao;
	
	@Autowired
	private NwAccountDao nwAcctDao;
	
	@Autowired
	private ISequenceService sequenceService;
	
	@Autowired
	private YeePayService yeePayService;
	
//	@Autowired
//	private IMatchService imatchService;
	
	
	@Override
	public boolean directBidCallOpr(long custId, BigDecimal userBidMoney, String prodCode, String projectNo, 
			String platForm,String requestNo) throws Exception {
		
		/** 1、更新债权的剩余金额及相关表（p2p_product */
		LoanClaimOriginVo loanClaim = loanclaimDao.selectClaimLoanDetailByProjectNo(projectNo);
		
		BigDecimal loanAmount = BigDecimal.ZERO; //直投类的合同金额
		if(loanClaim.getProjectType().equals(DictConstant.ProjectType.LOAN.getCode())){
			loanAmount = loanClaim.getLoanAmount();
			
		}else if(loanClaim.getProjectType().equals(DictConstant.ProjectType.CLAIM.getCode())){
			loanAmount = loanClaim.getRemainClaimAmount();
			
		}else{
			throw new Exception("未知类型，无法处理");
		}
		
		Product product = prodDao.getProductByProdCode(prodCode);
		BigDecimal remainAmount = product.getRemainAmount();
		
		BigDecimal[] calculateArray = ProgressUtils.calculate(userBidMoney, remainAmount, loanAmount);
		
		BigDecimal completedProgress = calculateArray[0];
		BigDecimal calRemainAmout = calculateArray[1]; //计算后的债权剩余可投金额
		
		Product updateProd = new Product();
		updateProd.setProductCode(product.getProductCode());
		updateProd.setInvestorCount(product.getInvestorCount()+1);
		updateProd.setRemainAmount(calRemainAmout);
		updateProd.setCompletedProgress(completedProgress);
		updateProd.setVersion(product.getVersion());
		
		int isCompleted = completedProgress.compareTo(BigDecimal.valueOf(100L));
		if(isCompleted == 0){
			updateProd.setFullScaleDate(new Date());
		}
		//TODO 更新项目状态为满标
		
		int updateProdResult = prodDao.updateProductByVersion(updateProd);
		
		boolean returnFlag = false;
		if(updateProdResult > 0){
			/** 更新用户账户余额 */
			Customer investCustomer = customerDao.selectByCustId(custId);
			
			String accountStatus = DictConstant.AccountStatus.NORMAL.getCode();
			CustAccount custAccount = custAcctDao.selectCustAcctByIdAndStatus(custId, accountStatus);
			
			BaseAccount baseAccount = baseAcctDao.selectByPrimaryKey(custAccount.getAccountNo());
			
			BigDecimal calUsableBalance = custAccount.getUsableBalance().subtract(userBidMoney);
			BigDecimal calFrozenBalance = custAccount.getForzenAmount().add(userBidMoney);
			BigDecimal calAllInvestBalance = custAccount.getAllInvestAmount().add(userBidMoney);
			
			CustAccount updateCustAcct = new CustAccount();
			updateCustAcct.setAccountNo(custAccount.getAccountNo());
			updateCustAcct.setCustId(custAccount.getCustId());
			updateCustAcct.setForzenAmount(calFrozenBalance);
			updateCustAcct.setUsableBalance(calUsableBalance);
			updateCustAcct.setUpdateTime(new Date());
			updateCustAcct.setAllInvestAmount(calAllInvestBalance);
			updateCustAcct.setVersion(custAccount.getVersion());
			
			int updateCustAcctResult = custAcctDao.updateByVersion(updateCustAcct);
			
			BaseAccount updateBaseAcct = new BaseAccount();
			updateBaseAcct.setAcctNo(custAccount.getAccountNo());
			updateBaseAcct.setAcctBal(calUsableBalance.add(calFrozenBalance));
			updateBaseAcct.setVersion(baseAccount.getVersion());
			
			int updateBaseAcctResult = baseAcctDao.updateByVersion(updateBaseAcct);
			
			if(updateCustAcctResult > 0 && updateBaseAcctResult > 0){
				
				String recordNo = sequenceService.getCompleteSequenceBySeqKey("TZJL"); //投资记录编号
				String investNo = sequenceService.getCompleteSequenceBySeqKey("TZJY"); //投资交易编号
				
				//借款人账户
				CustAccount otherCustAcct = custAcctDao.selectCustAcctByIdAndStatus(loanClaim.getLender(), accountStatus);
				BaseAccount otherBaseAccount = baseAcctDao.selectByPrimaryKey(otherCustAcct.getAccountNo());
				
				/** 写账户流水 */
				AccountFlow acctFlow = new AccountFlow();
				acctFlow.setSerialNo(sequenceService.getCompleteSequenceBySeqKey("ZJLS"));
				acctFlow.setAcctNo(custAccount.getAccountNo());
				acctFlow.setAcctName(baseAccount.getAcctName());
				acctFlow.setTransType(DictConstant.transactionType.FREEZE.getCode());
				acctFlow.setTransAmount(userBidMoney);
				acctFlow.setOtherAcctNo(otherCustAcct.getAccountNo()); 
				acctFlow.setOtherAcctName(otherBaseAccount.getAcctName());
				acctFlow.setAcctBal(calUsableBalance);
				acctFlow.setTransTime(new Date());
				acctFlow.setSummary("精选投标,冻结金额");
				acctFlow.setDealStatus(DictConstant.FlagStatus.Y.toString());
				acctFlow.setAcctKind(product.getProdKind());
				acctFlow.setProjectNo(projectNo);
				acctFlow.setFreezeAmount(calFrozenBalance);
				acctFlow.setProductCode(product.getProductCode());
				acctFlow.setRecordNo(recordNo);
				acctFlow.setInvestNo(investNo);
				acctFlow.setReqNo(requestNo);
				
				int insertAcctResult = acctFlowDao.insertSelective(acctFlow);
				
				if(insertAcctResult > 0){
					/** 写投资记录，非计划类需要多写一张表：p2p_invest_trans */
					String investMethod = "";
					if(product.getProdKind().equals(DictConstant.TempType.LOAN.toString())){
						investMethod = DictConstant.InvestMethod.DIRECT.getCode();
						
					}else if(product.getProdKind().equals(DictConstant.TempType.TRANSFER.toString())){
						investMethod = DictConstant.InvestMethod.TRANSFER.getCode();
						
					}else{
						throw new Exception("未知类型，无法处理,prodKind = " + product.getProdKind());
					}
					
					Date investDate = new Date();
					Date investEndDate = null;
					
					InvestProdRecord insertProdRecord = new InvestProdRecord();
					insertProdRecord.setRecordNo(recordNo);
					insertProdRecord.setProdCode(product.getProductCode());
					insertProdRecord.setGuaranteeId(loanClaim.getGuaranteeCorp());
					insertProdRecord.setGuaranteeName(loanClaim.getGuaranteeName());
					insertProdRecord.setYearRate(loanClaim.getInterestRate());
					insertProdRecord.setInvestAmount(userBidMoney);
					insertProdRecord.setInvestTerm(loanClaim.getLoanTerm());
					insertProdRecord.setTermType(loanClaim.getTimeType());
					insertProdRecord.setInvestTime(investDate);
					
					if(loanClaim.getTimeType().equals(DictConstant.TimeUit.D.getCode())){
						
						investEndDate = DateUtil.addDays(investDate, loanClaim.getLoanTerm());
					}else if(loanClaim.getTimeType().equals(DictConstant.TimeUit.M.getCode())){
						
						investEndDate = DateUtil.addMonths(investDate, loanClaim.getLoanTerm());
					}else if(loanClaim.getTimeType().equals(DictConstant.TimeUit.Y.getCode())){
						
						investEndDate = DateUtil.addYears(investDate, loanClaim.getLoanTerm());
					}else{
						throw new Exception("未知投资期限类型，无法处理");
					}
					insertProdRecord.setEndDate(investEndDate); //到期时间
					
					insertProdRecord.setInvestMethod(investMethod);
					insertProdRecord.setInvestStatus(DictConstant.INVEST_RECORD_STATUS.INVESTING.getCode());
					insertProdRecord.setCustId(custAccount.getCustId());
					insertProdRecord.setProdName(product.getProductName());
					insertProdRecord.setRemainAmount(BigDecimal.ZERO);
					insertProdRecord.setCustLoginName(investCustomer.getLoginName());
					
					int insertProdRecordResult = investProdRecordDao.insertSelective(insertProdRecord);
					
					InvestTrans insertTrans = new InvestTrans();
					insertTrans.setInvestNo(investNo);
					insertTrans.setProjectNo(loanClaim.getProjectNo());
					insertTrans.setCustId(custAccount.getCustId());
					insertTrans.setInvestAmount(userBidMoney);
					insertTrans.setStatus(DictConstant.INVEST_TRANS_STATUS.INVESTING.getCode());
					insertTrans.setInvestTime(new Date());
					insertTrans.setInvestMethod(investMethod);
					insertTrans.setRecordNo(recordNo);
					insertTrans.setProductCode(product.getProductCode());
					
					int insertTransResult = investTransDao.insertSelective(insertTrans);
					
					if(insertProdRecordResult > 0 && insertTransResult > 0){
						returnFlag = true;
					}else{
						throw new Exception("写投资记录失败");
					}
				}else{
					throw new Exception("写账户流水失败");
				}
			}else{
				throw new Exception("更新账户金额失败");
			}
		}else{
			throw new Exception("更新项目信息失败");
		}
		return returnFlag;
	}


	@Override
	public boolean planBidCallBackOpr(long custId, BigDecimal userBidMoney, String prodCode, String projectNo, 
			String platForm, String requestNo) throws Exception {
		
		boolean returnFlag = false;
		
		Product product = prodDao.getProductByProdCode(prodCode); 
		
		Map<String,Object> queryParamMap = new HashMap<String, Object>();
		queryParamMap.put("productCode", prodCode);
		InvestPlanProductVo planProd = planProdDao.getInvestPlanBySelective(queryParamMap);
		
		/** 1、如果是新客专享类计划，需要更新计划的完成进度及剩余募集金额 */
		if(planProd.getPlanProdType().equals(DictConstant.ProductType.PROD_NEW.getCode())){
			BigDecimal remainAmount = product.getRemainAmount();
			
			BigDecimal[] calculateArray = ProgressUtils.calculate(userBidMoney, remainAmount, 
					planProd.getCollectAmount());
			
			BigDecimal completedProgress = calculateArray[0];
			BigDecimal calRemainAmout = calculateArray[1]; //计算后的债权剩余可投金额
			
			Product updateProd = new Product();
			updateProd.setProductCode(product.getProductCode());
			updateProd.setInvestorCount(product.getInvestorCount()+1);
			updateProd.setRemainAmount(calRemainAmout);
			updateProd.setCompletedProgress(completedProgress);
			updateProd.setVersion(product.getVersion());
			
			int isCompleted = completedProgress.compareTo(BigDecimal.valueOf(100L));
			if(isCompleted == 0){
				updateProd.setFullScaleDate(new Date());
			}
			int updateProdResult = prodDao.updateProductByVersion(updateProd);
			
			if(updateProdResult <= 0){
				throw new Exception("更新计划余额失败");
			}
		}
		
		
		/** 1、更新用户账户的可用余额及冻结金额及相关表(p2p_cust_account、p2p_base_account) */
		Customer investCustomer = customerDao.selectByCustId(custId);
		
		String accountStatus = DictConstant.AccountStatus.NORMAL.getCode();
		CustAccount custAccount = custAcctDao.selectCustAcctByIdAndStatus(custId, accountStatus);
		
		BaseAccount baseAccount = baseAcctDao.selectByPrimaryKey(custAccount.getAccountNo());
	
		BigDecimal calUsableBalance = custAccount.getUsableBalance().subtract(userBidMoney);
		BigDecimal calFrozenBalance = custAccount.getForzenAmount().add(userBidMoney);
		BigDecimal calAllInvestBalance = custAccount.getAllInvestAmount().add(userBidMoney);
		
		CustAccount updateCustAcct = new CustAccount();
		updateCustAcct.setAccountNo(custAccount.getAccountNo());
		updateCustAcct.setCustId(custAccount.getCustId());
		updateCustAcct.setForzenAmount(calFrozenBalance);
		updateCustAcct.setUsableBalance(calUsableBalance);
		updateCustAcct.setAllInvestAmount(calAllInvestBalance);
		updateCustAcct.setVersion(custAccount.getVersion());
		int updateCustAcctResult = custAcctDao.updateByVersion(updateCustAcct);
		
		BaseAccount updateBaseAcct = new BaseAccount();
		updateBaseAcct.setAcctNo(custAccount.getAccountNo());
		updateBaseAcct.setAcctBal(calUsableBalance.add(calFrozenBalance));
		updateBaseAcct.setVersion(baseAccount.getVersion());
		int updateBaseAcctResult = baseAcctDao.updateByVersion(updateBaseAcct);
		
		if(updateCustAcctResult > 0 && updateBaseAcctResult > 0){
			
			String recordNo = sequenceService.getCompleteSequenceBySeqKey("TZJL"); //投资记录编号
			
			/** 写资金流水 */
			AccountFlow acctFlow = new AccountFlow();
			acctFlow.setSerialNo(requestNo);
			acctFlow.setAcctNo(custAccount.getAccountNo());
			acctFlow.setAcctName(baseAccount.getAcctName());
			acctFlow.setTransType(DictConstant.transactionType.FREEZE.getCode());
			acctFlow.setTransAmount(userBidMoney);
			acctFlow.setAcctBal(calUsableBalance);
			acctFlow.setTransTime(new Date());
			acctFlow.setSummary("投资计划，冻结金额");
			acctFlow.setDealStatus(DictConstant.FlagStatus.Y.toString());
			acctFlow.setAcctKind(baseAccount.getAcctKind());
			acctFlow.setProjectNo(projectNo);
			acctFlow.setFreezeAmount(calFrozenBalance);
			acctFlow.setProductCode(prodCode);
			acctFlow.setRecordNo(recordNo);
			acctFlow.setInvestNo(null);
			acctFlow.setReqNo(requestNo);
			int insertAcctFlowResult = acctFlowDao.insertSelective(acctFlow);
			
			if(insertAcctFlowResult > 0){
				Date investDate = new Date();
				InvestProdRecord insertProdRecord = new InvestProdRecord();
				
				insertProdRecord.setRecordNo(recordNo);
				insertProdRecord.setProdCode(product.getProductCode());
				insertProdRecord.setYearRate(planProd.getYearRate().add(product.getAddYield()));
				insertProdRecord.setInvestAmount(userBidMoney);
				insertProdRecord.setInvestTerm(planProd.getInvestTerm());
				insertProdRecord.setTermType(planProd.getTermType());
				insertProdRecord.setInvestTime(investDate);
				
				Date investEndDate = null;
				if(planProd.getTermType().equals(DictConstant.TimeUit.D.getCode())){
					
					investEndDate = DateUtil.addDays(investDate, planProd.getInvestTerm());
				}else if(planProd.getTermType().equals(DictConstant.TimeUit.M.getCode())){
					
					investEndDate = DateUtil.addMonths(investDate, planProd.getInvestTerm());
				}else if(planProd.getTermType().equals(DictConstant.TimeUit.Y.getCode())){
					
					investEndDate = DateUtil.addYears(investDate, planProd.getInvestTerm());
				}else{
					throw new Exception("未知投资期限类型，无法处理");
				}
				insertProdRecord.setEndDate(investEndDate); //到期时间
				
				insertProdRecord.setInvestMethod(DictConstant.InvestMethod.PLAN.getCode());
				insertProdRecord.setInvestStatus(DictConstant.INVEST_RECORD_STATUS.INVESTING.getCode());
				insertProdRecord.setCustId(custAccount.getCustId());
				insertProdRecord.setRemainAmount(userBidMoney);
				insertProdRecord.setProdName(product.getProductName());
				insertProdRecord.setCustLoginName(investCustomer.getLoginName());
				
				int insertInvestRecordResult = investProdRecordDao.insertSelective(insertProdRecord);
				
				if(insertInvestRecordResult > 0){
					returnFlag = true;
					
					/** 加入到待匹配资金队列 */
					Map<String,String> addFundMap = new HashMap<String, String>();
					addFundMap.put("user_id", String.valueOf(custId));
					addFundMap.put("_id", recordNo);
					addFundMap.put("invest_amount", userBidMoney.toString());
					addFundMap.put("invest_surplus_amount", userBidMoney.toString());
					addFundMap.put("version", "0");
					
//					imatchService.doAddFund(addFundMap);
				}else{
					throw new Exception("写投资记录失败");
				}
			}else{
				throw new Exception("写账户流水失败");
			}
		}else{
			throw new Exception("更新账户金额失败");
		}
		return returnFlag;
	}
	
	
}
